﻿////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// <copyright>Copyright 2008-2011 Andreas Huber Doenni</copyright>
// Distributed under the GNU General Public License version 2 (GPLv2).
// See accompanying file License.txt or copy at http://phuse.codeplex.com/license.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Phuse.Net.Nntp
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Threading;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Phuse.Mime;
    using Phuse.UnitTesting;

    /// <summary>Tests the <see cref="Client"/> class with a real server.</summary>
    [TestClass]
    public sealed class ServerTest : TestBase
    {
        /// <summary>Tests <see cref="PostCommand"/> by posting on a real server.</summary>
        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "PostTest", Justification = "Test code.")]
        [TestMethod]
        public void RealPostTest()
        {
            using (var client = TestServerHelper.GetTestServerClient())
            {
                var message = new Message()
                {
                    Fields = { new UnstructuredHeaderField("Newsgroups") { Body = "alt.test" } },
                    From = new List<Address>() { new Address("Andreas Huber", "ahd6974-spamboostorgtrap@yahoo.com") },
                    Subject = "Testing",
                    Date = DateTime.UtcNow,
                    MessageId = GetUniqueMessageId(),
                    Body = new TextBody(TextSubtypeNames.Plain) { Content = "ignore" }
                };

                new PostCommand(stream => message.WriteTo(stream)).Execute(client);
            }
        }

#if DEBUG
        /// <summary>Finds well-frequented newsgroups and writes their names into a file.</summary>
        [SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "Test code.")]
        [SuppressMessage("Microsoft.Security", "CA2140:TransparentMethodsMustNotReferenceCriticalCodeFxCopRule", Justification = "Test code.")]
        [TestMethod]
        public void ListNewsgroupsTest()
        {
            var groupList = new List<KeyValuePair<ActiveGroupInfo, DateTime>>(1024);

            using (var client = new Client("news.mozilla.org", CancellationToken.None))
            {
                using (var groups = new ListActiveCommand().Execute(client))
                {
                    while (groups.MoveNext())
                    {
                        var group = groups.Current;

                        if (group.HighWaterMark - group.LowWaterMark > 50000)
                        {
                            groupList.Add(new KeyValuePair<ActiveGroupInfo, DateTime>(group, DateTime.MinValue));
                        }
                    }
                }

                for (int index = 0; index < groupList.Count; ++index)
                {
                    var group = groupList[index].Key;
                    client.EnqueueCommand(new GroupCommand(group.GroupName));
                    client.EnqueueCommand(new OverCommand(group.HighWaterMark - 1000, group.HighWaterMark - 900));
                }

                int index2 = 0;

                while (client.PendingCommandsCount > 0)
                {
                    using (var overResponse = client.GetResponse() as OverResponse)
                    {
                        if (overResponse != null)
                        {
                            var group = groupList[index2].Key;

                            if (overResponse.MoveNext())
                            {
                                using (var overview = overResponse.Current.HeaderOverview)
                                {
                                    groupList[index2] = new KeyValuePair<ActiveGroupInfo, DateTime>(
                                        group, (DateTime)Message.Parse(overview).Date);
                                }
                            }

                            ++index2;
                        }
                    }
                }

                var dateComparer = Comparer<DateTime>.Default;
                groupList.Sort((l, r) => -dateComparer.Compare(l.Value, r.Value));

                using (var writer = File.CreateText("list.txt"))
                {
                    foreach (var group in groupList)
                    {
                        writer.WriteLine("{0,-80} {1,15}", group.Key.GroupName, group.Value);
                    }
                }
            }
        }
#endif

        /// <summary>Tests all NNTP related exceptions.</summary>
        [TestMethod]
        public void ExceptionTest()
        {
            TestStdExceptionConstructors<UnexpectedResponseException>();
            TestStdExceptionConstructors<ServiceUnavailableException>();
            TestStdExceptionConstructors<ServerFaultException>();
            TestStdExceptionConstructors<NoSuchGroupException>();
            TestStdExceptionConstructors<NoGroupSelectedException>();
            TestStdExceptionConstructors<InvalidCurrentArticleNumberException>();
            TestStdExceptionConstructors<NoNextArticleException>();
            TestStdExceptionConstructors<NoPreviousArticleException>();
            TestStdExceptionConstructors<NoSuchArticleException>();
            TestStdExceptionConstructors<PostingNotPermittedException>();
            TestStdExceptionConstructors<PostingFailedException>();
            TestStdExceptionConstructors<MissingAuthenticationException>();
            TestStdExceptionConstructors<AuthenticationFailedException>();
            TestStdExceptionConstructors<MissingPrivacyException>();
            TestStdExceptionConstructors<UnknownCommandException>();
            TestStdExceptionConstructors<CommandNotPermittedException>();
            TestStdExceptionConstructors<FeatureNotSupportedException>();
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        internal static string GetUniqueMessageId()
        {
            return "<" + GetUniqueString() + "@phuse.codeplex.com>";
        }
    }
}
